/*******************************************************************************
 * Copyright (c) 2011 TXT e-solutions SpA
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the research area ICT-2009.1.3
 * Internet of Things and enterprise environments.
 *
 *
 * Authors:
 *     Cristoforo Seccia (TXT e-solutions SpA)
 *
 * Contributors:
 *      Domenico Rotondi (TXT e-solutions SpA)
 *******************************************************************************/
package it.txt.access.capability.wizard.panel.controller;

import it.txt.access.capability.commons.filter.FilterXML;
import it.txt.access.capability.commons.signer.X509DocumentSigner;
import it.txt.access.capability.commons.utils.XMLPrinter;
import it.txt.access.capability.factory.CapabilitySchemaFactory;
import it.txt.access.capability.wizard.Wizard;
import it.txt.access.capability.wizard.WizardPanelController;
import it.txt.access.capability.wizard.panel.PanelAssertion;
import it.txt.access.capability.wizard.panel.exception.PanelAssertionException;
import it.txt.access.capability.wizard.panel.objects.PanelAssertionObject;
import java.awt.Component;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

import org.w3c.dom.Document;

/**
 *
 * @author Cristoforo Seccia (TXT e-solutions SpA)
 */
public class ControllerPanelAssertion extends WizardPanelController {

    private static final Logger logger = Logger.getLogger(ControllerPanelAssertion.class.getName());
    private Document capabilityDocument = null;
    private URI capabilityDocumentURI = null;
    private PanelAssertion panelAssertion;

    public ControllerPanelAssertion(Wizard wizard) {
        super(wizard);
        panelAssertion = new PanelAssertion(getWizard(), this);
    }

    @Override
    public Component getPanelComponent() {
        return panelAssertion;
    }

    @Override
    public boolean aboutToDisplayPanel() {
        try {
            recoverPaneAssertionObject(getBackwardObject());
            getWizard().setBackButtonEnabled(false);
            getWizard().setNextButtonEnabled(false);
            getWizard().setFinishButtonEnabled(false);
            getWizard().setCancelButtonEnabled(true);
            getWizard().setAccessRightsCreationPercentage(95);
            return true;
        } catch (PanelAssertionException ex) {
            JOptionPane.showMessageDialog(getWizard(), ex.getMessage(),
                    "Error", JOptionPane.ERROR_MESSAGE);
        }
        return false;
    }

    @Override
    public void displayingPanel() {

        Thread t = new Thread() {

            @Override
            public void run() {

                try {
                    // Recover all the needed objects.
                    PanelAssertionObject pao = (PanelAssertionObject) getBackwardObject();
                    panelAssertion.setProgressValue(0);

                    // Creating new Fragment Access Rights Capability (non signed)
                    panelAssertion.setProgressText("Creating unsigned access rights capability token ...");
                    capabilityDocument = CapabilitySchemaFactory.getInstance().createAccessRightsFragmentDocument(
                            pao.getAccessRightsCapabilityType());
                    panelAssertion.setProgressText("Unsigned access rights capability token created.");
                    panelAssertion.setProgressValue(25);
                    XMLPrinter.logDocumentElement(capabilityDocument.getDocumentElement(),
                            "Unsigned capability", false);
                    Thread.sleep(1000);

                    // Sign Access Rights Capability
                    panelAssertion.setProgressText("Signing the access rights capability token ...");
                    X509DocumentSigner.signXMLElement(capabilityDocument.getDocumentElement(), pao.getKeyValues(),
                            CapabilitySchemaFactory.SIGN_DOCUMENT_AFTER_NODE);
                    panelAssertion.setProgressText("Access rights capability successfully signed.");
                    panelAssertion.setProgressValue(50);
                    XMLPrinter.logDocumentElement(capabilityDocument.getDocumentElement(),
                            "Unsigned capability", false);
                    Thread.sleep(1000);

                    // Verify sign Access Rights Capability
                    panelAssertion.setProgressText("Verifying the digital signature ...");
                    if (X509DocumentSigner.verifyXMLElementSign(capabilityDocument.getDocumentElement())) {
                        logger.log(Level.INFO, "Signature verified!");
                    } else {
                        logger.log(Level.INFO, "Signature not verified!");
                    }
                    panelAssertion.setProgressText("Signature verified!");
                    XMLPrinter.logDocumentElement(capabilityDocument.getDocumentElement(),
                            "Signed capability", false);
                    panelAssertion.setProgressValue(75);

                    Thread.sleep(1000);
                    panelAssertion.setProgressText("Access rights capability successfully created and verified!");
                    panelAssertion.setProgressValue(100);

                    getWizard().setAccessRightsCreationPercentage(100);
                    getWizard().setFinishButtonEnabled(true);
                    getWizard().setCancelButtonEnabled(false);

                } catch (Exception ex) {
                    panelAssertion.setProgressValue(0);
                    panelAssertion.setProgressText("An error occurred: " + ex.getMessage());
                    logger.log(Level.INFO, ex.getMessage(), ex);
                }
            }
        };
        t.start();
    }

    @Override
    public boolean aboutToHidePanel() {
        return true;
    }

    public URI getSavedAccessRightCapabilityPath() throws PanelAssertionException {
        if (capabilityDocumentURI == null) {
            throw new PanelAssertionException("No Access Rights Capability saved.");
        } else {
            return capabilityDocumentURI;
        }
    }
    
    public Document getAccessRightsCapabilityToken () throws PanelAssertionException {
        if (capabilityDocument == null) {
            throw new PanelAssertionException("No Access Rights Capability token saved.");
        } else {
            return capabilityDocument;
        }
    }

    public boolean saveSignedAccessRightCapabilityFile(File assertionFile) {
        if (capabilityDocument != null) {
            String directory = assertionFile.getParentFile().getAbsolutePath();
            String fileName = assertionFile.getName();
            FilterXML fa = new FilterXML("Access Rights Capability");
            if (!fa.accept(assertionFile)) {
                fileName = fileName + "." + FilterXML.ASSERTION;
            }
            File saveFile = new File(directory, fileName);
            if (saveFile.exists()) {
                if (!getReplaceFileConfirmation()) {
                    return false;
                }
            }
            try {
                FileWriter fileWriter = new FileWriter(saveFile.toURI().getPath());

                fileWriter.append(
                        XMLPrinter.printDocumentElement(
                        capabilityDocument.getDocumentElement(), false));

                fileWriter.close();
                capabilityDocumentURI = saveFile.toURI();
                return true;
            } catch (IOException ex) {
                JOptionPane.showMessageDialog(getWizard(),
                        ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        }
        return false;
    }

    private PanelAssertionObject recoverPaneAssertionObject(Object backwardObject) throws PanelAssertionException {
        if (backwardObject == null) {
            throw new PanelAssertionException("Wizard panel object null.");
        }
        if (!(backwardObject instanceof PanelAssertionObject)) {
            throw new PanelAssertionException("No Panel Assertion Object defined.");
        }
        PanelAssertionObject pao = (PanelAssertionObject) backwardObject;
        if (pao.getAccessRightsCapabilityType() == null) {
            throw new PanelAssertionException("Panel Assertion Object Access Rights is Null.");
        }
        if (pao.getKeyValues() == null) {
            throw new PanelAssertionException("Panel Assertion Object Key Values is Null.");
        }
        return pao;
    }

    private boolean getReplaceFileConfirmation() {
        Object[] options = {"Yes, please", "No, thanks"};
        int resp = JOptionPane.showOptionDialog(getWizard(),
                "Replace the existing file?",
                "Save Access Rights File",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.QUESTION_MESSAGE,
                null,
                options,
                options[0]);
        return (resp == JOptionPane.YES_OPTION ? true : false);
    }
}
